from flask import Blueprint
from flask import request
from flask import render_template
from flask import flash
from flask import redirect
from flask import url_for
from flask import session

from app import db
from app.security import g
 
    

from app.wtforms.fase_forms import FaseBuscar
from app.wtforms.fase_forms import FaseCrear
from app.wtforms.fase_forms import FaseModificar
from app.wtforms.fase_forms import FaseConsultar
from app.wtforms.fase_forms import FaseSeleccionar
from app.wtforms.fase_forms import FaseImportar

from app.models.item import Item
from app.models.fase import Fase
from app.models.tipoItem import TipoItem
from app.models.atributo import Atributo
from app.models.entidad import Entidad
from app.models.permiso import Permiso
from app.security import permission


mod = Blueprint('fases', __name__, url_prefix='/fases')

@mod.route('/administracion/', methods=['GET', 'POST'])
@permission('ADMINISTRACION_FASES')
def administracion_fase():
    """
    Muestra en pantalla las fases que existen en el proyecto seleccionado.
    Si no recibe algun filtro como parametro, lista todas las fases.
    Si recibe algun filtro, muestra las fases que cumplen con el filtro indicado
    """    
    
    #Obtenemos el proyecto seleccionado
    proyecto_seleccionado = g.proyecto         
   
    if(proyecto_seleccionado != None):
        # Obtenemos el formulario   
        form =  FaseBuscar(request.form)
       
        # Obtenemos el filtro
        nombreFilter = form.nombre.data
        estadoFilter = form.estado.data
        
        if(nombreFilter == None):
            nombreFilter = ''
        if(estadoFilter == None):
            estadoFilter = ''        
        
        # Recuperamor de la base de datos las fases que coinciden con el filtro
        fases = Fase.query.filter(Fase.nombre.like( '%'+nombreFilter+'%' ), Fase.estado.like( '%'+estadoFilter+'%' ),  Fase.proyecto_id == proyecto_seleccionado.id)
        fases = fases.all() 
         
        return render_template('fase/administracion_fase.html', form = form, fases = fases)
    else:
        flash('No tiene permiso para ver esta pagina.')
        return redirect(url_for('acceso.home'))



@mod.route('/crear/', methods=['GET', 'POST'])
#@permission('CREAR_FASE')
def crear_fase():
    """
    Muestra en pantalla el formulario de creacion de fases, valida los datos ingresados por
    el usuario, hace las validaciones de que el nombre y la posicion de la nueva fase no existan en el
    sistema para el proyecto seleccionado y se hayan ingresado los datos obligatorios. 
    Luego almacena en base de datos.
    """
    
    if(verificar_autorizacion(g.user, g.proyecto, 'MODIFICAR')):
        #Obtenemos el proyecto seleccionado
        proyecto_seleccionado = g.proyecto
        
        #si el proyecto seleccionado no se encuentra con estado pendiente, no pueden crear fases
        if(proyecto_seleccionado.estado != 'Pendiente'):              
            flash('No se pueden crear fases para el proyecto seleccionado. El proyecto no se encuentra con estado PENDIENTE')  
            return redirect(url_for('fases.administracion_fase'))         
        else:              
            # Obtenemos el formulario
            form = FaseCrear(request.form)  
                            
            #obtenemos todas las fases del proyecto seleccionado
            fases=[]
            fases = Fase.query.filter(Fase.proyecto == proyecto_seleccionado)           
            fases = fases.all()            
            # Se valida los datos ingresados en el formulario
            if form.validate_on_submit():                
                contN = 0         
                # Comparamos que el nombre ingresado por el usuario no sea igual a uno existente
                if fases != []:
                    for faseind in fases:
                        if form.nombre.data == faseind.nombre:
                            contN = contN + 1
                                         
                # Si ya existe el nombre, no permitimos la creacion           
                if contN != 0:
                    flash("El nombre de la fase ya existe dentro del proyecto seleccionado, elija otro", 'error-message')
                    # Redirigimos a la pagina de administracion
                    return redirect(url_for('fases.crear_fase'))
                
                # Si el nombre aun no existe
                else:
                    nombre = form.nombre.data
                    estado = 'Pendiente'
                    
                    if form.fechainicio.data != None and form.fechainicio.data != '':
                        if form.fechafin.data != None and form.fechafin.data != '':
                            fechainicio = form.fechainicio.data
                            fechafin = form.fechafin.data
                            #verificamos la fecha
                            if fechainicio > fechafin:
                                flash("La fecha inicial debe ser menor a la fecha final", 'error-message')
                                # Redirigimos a la pagina de creacion
                                return redirect(url_for('fases.crear_fase'))
                            else:
                                fechafin = None
                    else:
                        if form.fechafin.data != None and form.fechafin.data != '':
                            flash("No se puede cargar una fecha final sin fecha inicial", 'error-message')
                            # Redirigimos a la pagina de creacion
                            return redirect(url_for('fases.crear_fase'))
                        else:
                            fechainicio = None
                            fechafin = None             
                                
                    ultimo = 0
                    for fase in fases:                
                        if(fase.posicion > ultimo):
                            ultimo = fase.posicion                     
                     
                    posicion = ultimo + 1
                    nombreProy = proyecto_seleccionado.nombre            
                    entidad = Entidad(nombre+" "+nombreProy)
                                  
                    # Creamos la fase
                    fase_carga = Fase(nombre, posicion, estado, fechainicio, fechafin, proyecto_seleccionado, entidad)
                    db.session.add(fase_carga)
                    db.session.commit()
                                                    
                    flash('La fase ha sido registrada con exito')
                    # Una vez creado la nueva fase, se redirecciona a la pagina de administracion     
                    return redirect(url_for('fases.administracion_fase'))                          
            return render_template('fase/crear_fase.html', form = form) 
    else:
        flash('NO TIENE PERMISOS PARA CREAR FASES') 
        return redirect(url_for('fases.administracion_fase'))
    

   
@mod.route('/modificar/<fase>/', methods=['GET', 'POST'])
#@permission('MODIFICAR_FASE')
def modificar_fase(fase):
    """
    Muestra en pantalla el formulario de modificacion de fases, valida los datos ingresados por
    el usuario, hace las validaciones del nombre y la posicion de la nueva fase, que no existan en el
    sistema para el proyecto seleccionado y se hayan ingresado los datos obligatorios. 
    Luego almacena en base de datos los cambios.
    :param fase:
    id de la fase que se desea modificar
    """     
    
    #Obtenemos la fase seleccionada
    fase_seleccionada = Fase.query.filter_by(id=fase).first()
    anterior = fase_seleccionada.nombre
    if(verificar_autorizacion_fase(g.user, fase_seleccionada, 'MODIFICAR')):
        #Obtenemos el proyecto seleccionado
        proyecto_seleccionado = g.proyecto
        
        #si el proyecto seleccionado no se encuentra con estado pendiente, no se puede modificar fases
        if(proyecto_seleccionado.estado == 'Finalizado' and proyecto_seleccionado.estado == 'Cancelado'):              
            flash('No se pueden modificar la fase para el proyecto seleccionado. El proyecto no se encuentra con estado Finalizado o Cancelado')  
            return redirect(url_for('fases.administracion_fase')) 
        
        else:   
            
            form = FaseModificar(request.form)  
            
            #obtenemos todas las fases del proyecto seleccionado
            fases = []
            fases = Fase.query.filter(Fase.proyecto == proyecto_seleccionado)          
            fases = fases.all()
            
            # verificamos que la/las fase/s anterior este/n finalizada/s
            contNF=0 
            for fase in fases:
                if fase.id != fase_seleccionada.id:
                    if fase.posicion < fase_seleccionada.posicion:
                        if fase.estado != 'Finalizada':
                            contNF=contNF+1
            
            if fase_seleccionada.estado == 'Pendiente': 
                choicesEstados = (('1','Pendiente'), ('2', 'Eliminada'))
                form.estado.choices = choicesEstados
                estFase = 0 
                    
            elif fase_seleccionada.estado == 'Finalizada': 
                choicesEstados = (('1','Finalizada'),('2','Finalizada'))
                form.estado.choices = choicesEstados
                estFase = 0 
            elif fase_seleccionada.estado == 'Eliminada':
                choicesEstados = (('1','Eliminada'), ('2', 'Eliminada'))
                form.estado.choices = choicesEstados   
                estFase = 1          
            else:
                if fase_seleccionada.estado == 'Activa' and contNF == 0: 
                    choicesEstados = (('1','Activa'), ('2','Finalizada'))
                    form.estado.choices = choicesEstados
                    estFase = 0 
                else:
                    choicesEstados = (('1','Activa'), ('2','Activa'))
                    form.estado.choices = choicesEstados
                    estFase = 0 
             
            # Se valida los datos ingresados en el formulario
            if form.validate_on_submit():
                
                posicionEstado = int(form.estado.data)                                      
                fase_seleccionada.estado =  choicesEstados[posicionEstado-1][1]
                items = []
                items =Item.query.filter(Item.fase == fase_seleccionada)
                items = items.all()
                
                               
                if fase_seleccionada.estado == 'Finalizada':
                    
                    if items ==[]:    
                        flash("La Fase no puede ser finalizada, no existen items dentro de la misma", 'error-message')
                        # Redirigimos a la pagina de modificacion
                        return redirect(url_for('fases.modificar_fase', fase = fase_seleccionada.id)) 
                    else:
                        # obtenemos los items de la fase a importar
                        contI=0                          
                        for item in items: 
                            if item.estado != 'Bloqueado':    
                                contI= contI + 1
                                                                   
                        # verificamos que todos los items de la fase seleccionada esten en estado bloqueado          
                        if contI != 0:
                            flash("La Fase no puede ser finalizada, existen items que no se encuentran en estado bloqueado", 'error-message')
                            # Redirigimos a la pagina de modificacion
                            return redirect(url_for('fases.modificar_fase', fase = fase_seleccionada.id))
                   
                        
                    # verificamos que la/las fase/s anterior este/n finalizada/s
                    contNF=0 
                    for fase in fases:
                        if fase.id != fase_seleccionada.id:
                            if fase.posicion < fase_seleccionada.posicion:
                                if fase.estado != 'Finalizada':
                                    contNF=contNF+1
                    
                    if contI != 0:
                        flash("La Fase no puede ser finalizada, existen fases de posiciones anteriores no finalizadas", 'error-message')
                        # Redirigimos a la pagina de modificacion
                        return redirect(url_for('fases.modificar_fase', fase = fase_seleccionada.id))
                    
                
                if (anterior != form.nombre.data and estFase == 1):
                    flash("El nombre de la fase no puede ser modificada, la fase se encuentra con estado Eliminada", 'error-message')
                    # Redirigimos a la pagina de modificacion
                    return redirect(url_for('fases.modificar_fase', fase = fase_seleccionada.id))
                else:
                    contN = 0           
                    # Comparamos que el nombre ingresado por el usuario no sea igual a uno existente
                    if fases != []:
                        for faseind in fases:
                            if fase_seleccionada.id != faseind.id:
                                if form.nombre.data == faseind.nombre:
                                    contN = contN + 1
                                 
                    # Si ya existe el nombre, no permitimos la creacion           
                    if contN != 0:
                        flash("El nombre de la fase ya existe dentro del proyecto seleccionado, elija otro", 'error-message')
                        # Redirigimos a la pagina de modificacion
                        return redirect(url_for('fases.modificar_fase', fase = fase_seleccionada.id))
    
                    
                    if form.fechainicio.data != None and form.fechainicio.data != '':
                        if form.fechafin.data != None and form.fechafin.data != '':                              
                            fechainicio = form.fechainicio.data
                            fechafin = form.fechafin.data
                            #verificamos la fecha
                            if fechainicio > fechafin:
                                flash("La fecha inicial debe ser menor a la fecha final", 'error-message')
                                # Redirigimos a la pagina de creacion
                                return redirect(url_for('fases.modificar_fase', fase = fase_seleccionada.id)) 
                            
                    else:
                        if form.fechafin.data != None and form.fechafin.data != '':
                            flash("No se puede cargar una fecha final sin fecha inicial", 'error-message')
                            # Redirigimos a la pagina de creacion
                            return redirect(url_for('fases.modificar_fase', fase = fase_seleccionada.id)) 
                        
                        
                    # Realizamos los cambios en los atributos de la fase      
                    fase_seleccionada.setNombre(form.nombre.data)
                    fase_seleccionada.setEstado(fase_seleccionada.estado)
                    #fase_seleccionada.setPosicion(int(form.posicion.data))
                                                     
                    if form.fechainicio.data != None and form.fechainicio.data != '':
                        fase_seleccionada.fechainicio = form.fechainicio.data
                    else:
                        fase_seleccionada.fechainicio = None
                           
                    if form.fechafin.data != None and form.fechafin.data != '':
                        fase_seleccionada.fechafin = form.fechafin.data
                    else:
                        fase_seleccionada.fechafin = None 
                        
                    # Almacenamos la fase modificada en la base de datos
                    db.session.add(fase_seleccionada)
                    db.session.commit()
                    # Retornamos a la pagina de administracion de fases
                    flash('La fase ha sido actualizada con exito')
                    return redirect(url_for('fases.administracion_fase')) 
             
            
            # Mostramos en el formulario los datos actuales de la fase seleccionada
            form.nombre.data = fase_seleccionada.nombre
            form.fechainicio.data = fase_seleccionada.fechainicio
            form.fechafin.data = fase_seleccionada.fechafin
            
            
            return render_template('fase/modificar_fase.html', form = form, fase_seleccionada=fase_seleccionada)  
    else:
        flash('NO TIENE PERMISOS PARA MODIFICAR LA FASE SELECCIONADA') 
        return redirect(url_for('fases.administracion_fase'))     
 
 
 
    
@mod.route('/consultar/<fase>/', methods=['GET', 'POST'])
#@permission('VER_FASE')
def consultar_fase(fase):
    """
    Muestra en pantalla el formulario de consulta de fases, muestra todos los datos de la
    fase seleccionada
    :param fase:
    id de la fase que se desea consultar
    """
    
    # Obtenemos la fase seleccionada
    fase_seleccionada = Fase.query.filter_by(id=fase).first()

    if(verificar_autorizacion_fase(g.user, fase_seleccionada, 'VER')):
        #Obtenemos el formulario
        form = FaseConsultar(request.form)
        
        # Obtenemos los tipos de items si existen de la fase seleccionada
        tipoItems =TipoItem.query.filter(TipoItem.fase == fase_seleccionada)            
        # Hacemos una tupla con el nombre del tipoItem y su id
        lista_tipoItems=[]
        for tipoItem in tipoItems:
            lista_tipoItems.append((tipoItem.id, tipoItem.nombre))
            
            
        # Obtenemos los items si existen de la fase seleccionada
        items =Item.query.filter(Item.fase == fase_seleccionada)            
        # Hacemos una tupla con el nombre del tipoItem y su id
        lista_items=[]
        for item in items:
            lista_items.append((item.id, item.nombre))
        
        
        # Mostramos en el formulario los datos actuales de la fase seleccionada
        form.nombre.data = fase_seleccionada.nombre
        form.estado.data = fase_seleccionada.estado
        form.posicion.data = str(fase_seleccionada.posicion)
        form.fechainicio.data = fase_seleccionada.fechainicio
        form.fechafin.data = fase_seleccionada.fechafin  
        form.tipoItems.choices = lista_tipoItems
        form.items.choices = lista_items
           
        
        if form.validate_on_submit():            
            #Cuando el usuario presiona aceptar, redirigimos a la pagina de administracion de fases
            return redirect(url_for('fases.administracion_fase'))        
        return render_template('fase/consultar_fase.html', form = form, 
                               fase_seleccionada=fase_seleccionada)
    else:
        flash('NO TIENE PERMISOS PARA VISUALIZAR LA FASE SELECCIONADA') 
        return redirect(url_for('fases.administracion_fase'))
        
        

@mod.route('/eliminar/<fase>/', methods=['GET', 'POST'])
#@permission('ELIMINAR_FASE')
def eliminar_fase(fase):
    # Obtenemos la fase seleccionada
    fase_seleccionada = Fase.query.filter_by(id=fase).first()
    
    if(verificar_autorizacion_fase(g.user, fase_seleccionada, 'ELIMINAR')):

        #Obtenemos el proyecto seleccionado
        proyecto_seleccionado = g.proyecto
        
        #si el proyecto seleccionado no se encuentra con estado pendiente, no puede eliminar fases
        if(proyecto_seleccionado.estado != 'Pendiente'):  
            
            flash('No se pueden eliminar fases para el proyecto seleccionado. El proyecto no se encuentra con estado PENDIENTE')  
            return redirect(url_for('fases.administracion_fase')) 
        
        else: 
            #obtenemos la posicion de la fase a eliminar
            posicion = fase_seleccionada.posicion
            
            #cambiamos el estado de la fase a elminada
            if(fase_seleccionada.estado != 'Eliminada'):
                fase_seleccionada.estado = 'Eliminada' 
                #actualizamos los datos de la fase eliminada
                fase_seleccionada.posicion=0
                db.session.add(fase_seleccionada)
                db.session.commit()                
            
                #obtenemos todas las fases del proyecto
                fases = Fase.query.filter(Fase.proyecto == proyecto_seleccionado)
                #cambiamos las posiciones de las fases
                
                for fase in fases:
                    if fase.id != fase_seleccionada.id:
                        if posicion < fase.posicion:
                            fase_sec = Fase.query.filter_by(id=fase.id).first()
                            fase_sec.posicion = fase.posicion - 1
                            db.session.add(fase_sec)
                            db.session.commit()
                        
                # Redirigimos a la pagina de administracion de fases
                flash('La fase ha sido eliminada con exito')
                return redirect(url_for('fases.administracion_fase'))

    else:
        flash('NO TIENE PERMISOS PARA ELIMINAR LA FASE SELECCIONADA') 
        return redirect(url_for('fases.administracion_fase')) 
      
    



@mod.route('/seleccionar/', methods=['GET', 'POST'])
def seleccionar_fase():
    if(verificar_autorizacion(g.user, g.proyecto, 'MODIFICAR')):

        #Obtenemos el proyecto seleccionado
        proyecto_seleccionado = g.proyecto
        
        #si el proyecto seleccionado no se encuentra con estado pendiente, no se puede importar fases
        if(proyecto_seleccionado.estado != 'Pendiente'):            
            flash('No se pueden importar fases para el proyecto seleccionado. El proyecto no se encuentra con estado PENDIENTE')  
            return redirect(url_for('fases.administracion_fase')) 
        
        else:              
            # Obtenemos el formulario para importar fases
            form = FaseSeleccionar(request.form)  
                            
            # Obtenemos todos las fases existentes en la base de datos
            fases =Fase.query.all()
            
            # Hacemos una tupla con el nombre de la fase y su id
            lista_fases=[]
            for fase in fases:
                lista_fases.append((fase.id, fase.nombre +" "+ fase.proyecto.nombre))               
            
            # Asignamos esa tupla de fases a la lista que va a ser visualizada  
            form.fases.choices = lista_fases
            
            
            if form.validate_on_submit():
                # Obtenemos la fase seleccionada por el usuario
                session['fase_id'] = form.fases.data
                return redirect(url_for('fases.importar_fase'))       
                 
            return render_template('fase/seleccionar_fase.html', form = form)
    else:
        flash('NO TIENE PERMISOS PARA IMPORTAR FASES') 
        return redirect(url_for('fases.administracion_fase'))


  
@mod.route('/importar/', methods=['GET', 'POST'])
def importar_fase():
    
    """
    Muestra en pantalla el formulario de importar fases
    """
    
    if(verificar_autorizacion(g.user, g.proyecto, 'MODIFICAR')):
    
        #Obtenemos el proyecto seleccionado
        proyecto_seleccionado = g.proyecto
        
        # Obtenemos el formulario
        form = FaseImportar(request.form)
        
        # Obtenemos la fase seleccionada
        fase = session['fase_id']
        fase_seleccionada = Fase.query.filter_by(id=fase[0]).first() 
             
        #obtenemos todas las fases del proyecto seleccionado
        fases=[]
        fases = Fase.query.filter(Fase.proyecto == proyecto_seleccionado)            
        fases = fases.all()  
        # obtenemos los tipo de items de la fase a importar
        tipoItems =TipoItem.query.filter(TipoItem.fase == fase_seleccionada) 
        lista_tipoItems=[]
        for tipoItem in tipoItems:
            lista_tipoItems.append((tipoItem.id, tipoItem.nombre))
            
        # obtenemos los items de la fase a importar
        items =Item.query.filter(Item.fase == fase_seleccionada)
        items= items.all() 
        lista_items=[]
        for item in items:
            lista_items.append((item.id, item.nombre))
        
        # Se aceptan los datos de la fase
        if form.validate_on_submit():            
            contN = 0         
            # Comparamos que el nombre ingresado por el usuario no sea igual a uno existente
            if fases != []:
                for faseind in fases:
                    if form.nombre.data == faseind.nombre:
                        contN = contN + 1
                                     
            # Si ya existe el nombre, no permitimos la creacion           
            if contN != 0:
                flash("El nombre de la fase ya existe dentro del proyecto seleccionado, elija otro", 'error-message')
                # Redirigimos a la pagina de administracion
                return redirect(url_for('fases.importar_fase', fase = fase_seleccionada.id))
            
            # Si el nombre aun no existe
            else:
                nombre = form.nombre.data
                estado = 'Pendiente'
                
                if form.fechainicio.data != None and form.fechainicio.data != '':
                    if form.fechafin.data != None and form.fechafin.data != '':
                        fechainicio = form.fechainicio.data
                        fechafin = form.fechafin.data
                        #verificamos la fecha
                        if fechainicio > fechafin:
                            flash("La fecha inicial debe ser menor a la fecha final", 'error-message')
                            # Redirigimos a la pagina de creacion
                            return redirect(url_for('fases.crear_fase'))
                        else:
                            fechafin = None
                else:
                    if form.fechafin.data != None and form.fechafin.data != '':
                        flash("No se puede cargar una fecha final sin fecha inicial", 'error-message')
                        # Redirigimos a la pagina de creacion
                        return redirect(url_for('fases.crear_fase'))
                    else:
                        fechainicio = None
                        fechafin = None              
                                
                ultimo = 0
                for fase in fases:                
                    if(fase.posicion > ultimo):
                        ultimo = fase.posicion                     
                 
                posicion = ultimo + 1
                nombreProy = proyecto_seleccionado.nombre            
                entidad = Entidad(nombre+" "+nombreProy)
                            
                # Creamos la fase
                fase_carga = Fase(nombre, posicion, estado, fechainicio, fechafin, proyecto_seleccionado, entidad)
                db.session.add(fase_carga)
                db.session.commit()
                
                #creamos el tipo de item para la fase importada si existe
                lista_atributos=[]
                for tipo in tipoItems:     
                    if tipo != None:  
                        # Obtenemos los atributos del tipo de item             
                        for id_atributo in tipo.atributo:    
                            atributo = Atributo.query.filter_by(id=id_atributo.id).first()
                            lista_atributos.append(atributo)
                        tipoItem_carga = TipoItem(tipo.nombre,lista_atributos,proyecto_seleccionado, fase_carga)
                        db.session.add(tipoItem_carga)
                        db.session.commit()
                           
                flash('La fase ha sido registrada con exito')
                # Una vez creado la nueva fase, se redirecciona a la pagina de administracion     
                return redirect(url_for('fases.administracion_fase')) 
            
        # Mostramos en el formulario los datos actuales de la fase a importar
        form.nombre.data = fase_seleccionada.nombre
        form.tipoItems.choices = lista_tipoItems
        form.items.choices = lista_items
         
        return render_template('fase/importar_fase.html', form = form)
    else:
        flash('NO TIENE PERMISOS PARA IMPORTAR FASES') 
        return redirect(url_for('fases.administracion_fase'))




def verificar_autorizacion(usuario = None, proyecto = None, permisoRequerido = None):
    
    autorizado = False

    permiso = db.session.query(Permiso).filter_by(nombre = permisoRequerido, entidad_id = proyecto.entidad_id).first()
       
    if(permiso != None):
        for rol in usuario.roles:
            if permiso in rol.permiso:
                autorizado = True
    
    return autorizado



def verificar_autorizacion_fase(usuario = None, fase = None, permisoRequerido = None):
    
    autorizado = False

    permiso = db.session.query(Permiso).filter_by(nombre = permisoRequerido, entidad_id = fase.entidad_id).first()
    if(permiso != None):
        for rol in usuario.roles:
            if permiso in rol.permiso:
                autorizado = True
    
    return autorizado
    
